package br.com.infocruz.seam.crm.ejb.jpa;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.FlushModeType;
import javax.persistence.Query;
import javax.persistence.TemporalType;

import br.com.infocruz.seam.crm.ejb.model.AbstractEntity;
import br.com.infocruz.seam.crm.ejb.model.EntityList;

public class JpaQuery<T extends AbstractEntity> implements Query {

	/**
	 * 
	 */
	private static final long serialVersionUID = -384685075564547041L;
	
	private Query query;
	private Query queryCount;
	
	private int firstResult;
	private int maxResults;
	
	private JpaQueryBuilder<T> queryBuilder; 

	public JpaQuery(String ejbql) {
		this(ejbql, -1, 0);
	}
	
	public JpaQuery(String ejbql, Integer maxResults, Integer firstResult) {
		this(ejbql, maxResults, firstResult, null, null);
	}
	
	public JpaQuery(String ejbql, String orderDirection, String orderColumn) {
		this(ejbql, null, null, orderDirection, orderColumn);
	}
	
	public JpaQuery(String ejbql, Integer maxResults, Integer firstResult, String orderDirection, String orderColumn) {
		super();
		queryBuilder = new JpaQueryBuilder<T>(ejbql);
		queryBuilder.setOrderDirection(orderDirection);
		queryBuilder.setOrderColumn(orderColumn);
		query = queryBuilder.createQuery();
		if (maxResults != null) {
			setMaxResults(maxResults);
		}
		if (firstResult != null) {
			setFirstResult(firstResult);
		}
		queryCount = queryBuilder.createCountQuery();
	}
	
	// *-*-*-* begin delegate
	
	public int executeUpdate() {
		return query.executeUpdate();
	}

	@SuppressWarnings("unchecked")
	public List<T> getResultList() {
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public T getSingleResult() {
		return (T)query.getSingleResult();
	}

	public JpaQuery<T> setFirstResult(int startPosition) {
		this.firstResult = startPosition;
		query.setFirstResult(startPosition);
		return this;
	}

	public JpaQuery<T> setFlushMode(FlushModeType flushMode) {
		query.setFlushMode(flushMode);
		return this;
	}

	public JpaQuery<T> setHint(String hintName, Object value) {
		query.setHint(hintName, value);
		return this;
	}

	public JpaQuery<T> setMaxResults(int maxResults) {
		this.maxResults = maxResults;
		query.setMaxResults(maxResults);
		return this;
	}

	public JpaQuery<T> setParameter(int position, Calendar value, TemporalType temporalType) {
		queryCount.setParameter(position, value, temporalType);
		query.setParameter(position, value, temporalType);
		return this;
	}

	public JpaQuery<T> setParameter(int position, Date value, TemporalType temporalType) {
		queryCount.setParameter(position, value, temporalType);
		query.setParameter(position, value, temporalType);
		return this;
	}

	public JpaQuery<T> setParameter(int position, Object value) {
		queryCount.setParameter(position, value);
		query.setParameter(position, value);
		return this;
	}

	public JpaQuery<T> setParameter(String name, Calendar value, TemporalType temporalType) {
		queryCount.setParameter(name, value, temporalType);
		query.setParameter(name, value, temporalType);
		return this;
	}

	public JpaQuery<T> setParameter(String name, Date value, TemporalType temporalType) {
		queryCount.setParameter(name, value, temporalType);
		query.setParameter(name, value, temporalType);
		return this;
	}

	public JpaQuery<T> setParameter(String name, Object value) {
		queryCount.setParameter(name, value);
		query.setParameter(name, value);
		return this;
	}

	// *-*-*-* end delegate
	
	public Long getResultCount() {
		return (Long)queryCount.getSingleResult();
	}
	
	public EntityList<T> getEntityList() {
		List<T> resultList = getResultList();
		int resultCount = getResultCount().intValue();
		EntityList<T> entityList = new EntityList<T>(resultList, resultCount, firstResult, maxResults);
		return entityList;
	}
	
}